Microsoft Windows NT® and Windows® 95/98 do not currently support real-time scheduling of CPU resources. For example, with Windows NT®, all interrupts and deferred procedure calls must be completed before execution of a “real-time” priority NT thread. Even more problematic is the fact that third-party virtual device drivers can disable all interrupts in Windows® 95/98. Further, thread execution on these operating systems is scheduled based on the idea of a thread priority. Threads of equal priority split the CPU resources equally. There is no concept of allocating CPU resources to a thread on a periodic or single shot basis. In addition, there is no up front failure if the required CPU resources are not available because other clients have already reserved the needed CPU bandwidth. Consequently, even the highest priority threads can have their execution delayed for indeterminate periods of time in both operating systems.
The Windows NT® driver model allows execution in 3 different fundamental layers of the OS, at interrupt time, at DPC time, and at thread execution time. Interrupts are run before anything else. If there is an interrupt pending, and it can be serviced, then servicing it will happen before anything else. After all hardware interrupts are serviced, any pending deferred procedure calls (DPCs) are executed. These DPCs are run in a software interrupt. The DPCs can be interrupted by other interrupts that have a higher priority, but they will all be run before execution of the interrupted thread resumes. After all interrupts have been serviced, and all queued DPCs have been run, then the operating system resumes running a thread. All application level code is run in a thread. Most of the operating system code also runs in threads at a passive level.
Well-written Windows NT® drivers spend very little time in their interrupt service routine (ISR). NT device drivers are supposed to do most of their work in a DPC. Thus, well-written drivers do little more in their ISR besides touch their hardware to clear the interrupt, and queue up a DPC in which they will do most of their work. The vast majority of NT drivers are well behaved so interrupt latency on NT is very low, usually on the order of tens of nanoseconds to microseconds. A DPC can run on any processor and in any thread context. On a uni-processor system all DPCs must complete before the system will return to running the thread whose execution was interrupted. On a multiple processor machine, it is possible to have one processor running a thread while a different processor is servicing an interrupt, or running a DPC.
There are two primary obstacles to guaranteed, hard periodic scheduling of threads on Windows NT®. First, there is no API defined to specify to the operating system what periodicity and CPU resources a thread requires. Second, interrupts and DPCs hold off execution of all threads, and the length of time those interrupts and DPCs can run is unbounded.
On Microsoft Windows® 95 and 98 the situation is worse. There are a significant number of poorly-written third-party device drivers (i.e. V×Ds) that disable all interrupts on the operating system. Sometimes, these device drivers will disable interrupts for extended periods of time. When interrupts are disabled nothing else in the system can run except the code that turned off interrupts. On Windows NT® it is considered unacceptable to turn off all interrupts. There are very few places in the Windows NT® kernel where all interrupts are turned off. However, on Windows® 95 and 98 originally, the only way to disable one interrupt was to disable them all. There was no concept in the operating systems of multiple interrupt request levels (IRQL). Interrupts were either enabled, or disabled, and the only priority relationships between interrupts were those imposed by the programmable interrupt controller (PIC) at the hardware level. In the software, all interrupts were treated equally. In fact, the kernel interrupt service code actually muddled the priority relationships between interrupts that were imposed at the hardware level. Since it made it possible for a lower priority interrupt at the hardware level to interrupt code that serviced hardware with an interrupt at a higher priority level if the interrupt service routine for the higher priority interrupt enabled interrupts.
This situation changed somewhat with Windows® 98 when the Windows Driver Model (WDM) support was added to the operating system. At least for WDM drivers, there was now the concept of IRQL and interrupt priority levels in the software. However, all of the legacy third-party device drivers continue to run the same way they previously operated. All of the legacy kernel system code still deals with interrupts as either ON or OFF. Consequently, even in Windows® 98, there is code all over the operating system and in third-party device drivers that disables interrupts.
In order to perform any real-time scheduling on Windows® 95/98, something must be done to solve the problem of how to get control from the existing code when interrupts are disabled. The assembly language instruction for turning off maskable interrupts is CLI. To re-enable interrupts the instruction is STI. Interrupts can also be enabled in ring 0 code by popping the EFLAGS register off of the stack. There are CLIs, STIs, and PUSHFD, POPFD instructions all through the Windows® 95/98 code base. Unless control of the CPU can be taken away from code that is running with interrupts disabled, there is no hope of enabling guaranteed-hard-real-time scheduling. Scheduled threads will not be allowed to run until after the STI instruction is executed.
Accordingly, it is an object of the present invention to provide improved methods and computer-executable components for facilitating real-time scheduling of CPU resources.